package com.linked.gateway.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.linked.commonentity.basemanage.generallog.LinkedGeneralLog;
import com.linked.commonentity.basemanage.generallog.LinkedProject;
import com.linked.gateway.config.GateWaySecuritySetting;
import com.linked.gateway.config.GatewayNoLoginConfig;
import com.linked.gateway.config.GatewaySwitchConfig;
import com.linked.gateway.feign.IBaseManageFeign;
import com.linked.universal.common.LinkedToken;
import com.linked.universal.linkedutil.HashUtil;
import com.linked.universal.linkedutil.LinkedRedisKeys;
import com.linked.universal.linkedutil.RSAUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;


/**
 * @author :dbq
 * @date : 2022/10/25 15:07
 */
@Component
public class TokenFilter implements GlobalFilter, Ordered {


    private final static Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);

    private final ObjectMapper mapper;

    private final GatewaySwitchConfig switchConfig;

    private final GateWaySecuritySetting securitySetting;

    private final GatewayNoLoginConfig noLoginConfig;

    private final IBaseManageFeign baseManageFeign;

    private final StringRedisTemplate redisTemplate;

//    private final static String REDISKEY_TOKEN = "active_token_userId:";

    @Autowired
    public TokenFilter(ObjectMapper mapper, GatewaySwitchConfig switchConfig, GateWaySecuritySetting securitySetting,
                       GatewayNoLoginConfig noLoginConfig, IBaseManageFeign baseManageFeign, StringRedisTemplate redisTemplate) {
        this.mapper = mapper;
        this.switchConfig = switchConfig;
        this.securitySetting = securitySetting;
        this.noLoginConfig = noLoginConfig;
        this.baseManageFeign = baseManageFeign;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("token过滤器 访问路径：" + request.getURI().toString());
        }
        /**
         * 一、token验证
         * */
        String methodUrl = request.getPath().toString();

        if (switchConfig.isTokenSwitch() && !noLoginConfig.getMethodUrl().contains(methodUrl)) {

            /**
             * 一、获取header中的token
             * */
            HttpHeaders headers = request.getHeaders();
            String tokenStr = headers.getFirst("Authentication");
            if (StringUtils.isEmpty(tokenStr)) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Base64 token :" + tokenStr);
            }
            /**
             * 二、校验token有效性
             * */
            LinkedToken linkedToken = null;
            try {
                byte[] token_bytes = HashUtil.decryptBASE64(tokenStr);
                linkedToken = mapper.readValue(token_bytes, LinkedToken.class);
//            linkedToken = JSONObject.parseObject(tokenStr, LinkedToken.class);
            } catch (Exception e) {
                LOGGER.error("token Json字符串转实体类异常！", e);
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            try {
                String path = request.getPath().toString();
                String[] urls = path.split("/");
                String project = urls[1];
                String method = new StringBuilder().append('/').append(urls[2]).append('/').append(urls[3]).toString();
                baseManageFeign.insertGeneralLog(
                        LinkedGeneralLog.Builder().
                                withLogProject(LinkedProject.Linked_Gateway).
                                withLogPosition(path).
                                withTraceId(linkedToken.getUserId()));
            } catch (Exception e) {
                LOGGER.error("插入日志异常！", e);
            }

            //1、签名验证
            LinkedToken tempData = new LinkedToken();
            try {
                tempData.setUserId(linkedToken.getUserId());
                tempData.setExpirTime(linkedToken.getExpirTime());
                boolean ret = RSAUtil.verify(mapper.writeValueAsBytes(tempData), securitySetting.getPubicKey(), linkedToken.getToken());
                if (!ret) {
                    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                    return exchange.getResponse().setComplete();
                }
            } catch (Exception e) {
                LOGGER.error("token 验签异常！", e);
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

            boolean ifLoginRedis = baseManageFeign.findSwitchStatus("IF_LOGIN_INFO_REDIS");
            //2、时间校验
            if (ifLoginRedis && redisTemplate.hasKey(LinkedRedisKeys.REDISKEY_TOKEN + tempData.getUserId())) {
                redisTemplate.expire(LinkedRedisKeys.REDISKEY_TOKEN + tempData.getUserId(), 1, TimeUnit.HOURS);
            } else {
                if (LocalDateTime.now().isAfter(linkedToken.getExpirTime())) {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("token已超时！");
                    }
                    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                    return exchange.getResponse().setComplete();
                }
//                if (LOGGER.isInfoEnabled()) {
//                    LOGGER.info("token已超时！");
//                }
//                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
//                return exchange.getResponse().setComplete();
            }

        }
        /**
         * 二、正常访问
         * */
        ServerHttpResponse response = exchange.getResponse();
        return chain.filter(exchange);
    }

//    private boolean tokenHandle(ServerHttpRequest request) {
//
//
//        /**
//         * 一、获取header中的token
//         * */
//        HttpHeaders headers = request.getHeaders();
//        String tokenStr = headers.getFirst("Authentication");
//        if (StringUtils.isEmpty(tokenStr)) {
//            return false;
//        }
//        if (LOGGER.isInfoEnabled()) {
//            LOGGER.info("Base64 token :" + tokenStr);
//        }
//        /**
//         * 二、校验token有效性
//         * */
//        LinkedToken linkedToken = null;
//        try {
//            byte[] token_bytes = HashUtil.decryptBASE64(tokenStr);
//            linkedToken = mapper.readValue(token_bytes, LinkedToken.class);
////            linkedToken = JSONObject.parseObject(tokenStr, LinkedToken.class);
//        } catch (Exception e) {
//            LOGGER.error("token Json字符串转实体类异常！", e);
//            return false;
//        }
//        try {
//            String path = request.getPath().toString();
//            String[] urls = path.split("/");
//            String project = urls[1];
//            String method = new StringBuilder().append('/').append(urls[2]).append('/').append(urls[3]).toString();
//            baseManageFeign.insertGeneralLog(GeneralLogInfo.Builder().withLogProject(project).withLogPosition(method).withTraceId(linkedToken.getUserId()));
//        } catch (Exception e) {
//            LOGGER.error("插入日志异常！", e);
//        }
//
//        //1、签名验证
//        try {
//            LinkedToken tempData = new LinkedToken();
//            tempData.setUserId(linkedToken.getUserId());
//            tempData.setExpirTime(linkedToken.getExpirTime());
//            boolean ret = RSAUtil.verify(mapper.writeValueAsBytes(tempData), securitySetting.getPubicKey(), linkedToken.getToken());
//            if (!ret) {
//                return false;
//            }
//        } catch (Exception e) {
//            LOGGER.error("token 验签异常！", e);
//            return false;
//        }
//        //2、时间校验
//        if (LocalDateTime.now().isAfter(linkedToken.getExpirTime())) {
//            if (LOGGER.isInfoEnabled()) {
//                LOGGER.info("token已超时！");
//            }
//            return false;
//        }
//        return true;
//    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE + 2;
    }
}
